from app.schema.user_schema import UserLogin, UserLoginResponse, UserCreate,UserInfoResponse,ChangePasswordRequest,UpdateUserInfoRequest
from app.schema.user_schema import UserLogin, UserLoginResponse, UserCreate,UserInfoResponse,ChangePasswordRequest,UserWithPermissionsResponse
from app.repositories import user_repo,user_permission_repo
from app.utilities.error import Error
from passlib.hash import bcrypt
from sqlalchemy.orm import Session
from app.utilities.response import SuccessResponse
from typing import Optional,List
from ..models.coop_app.user import User


from ..utilities.jwt_token import create_access_token

# finish register and login
def _generate_login_response(user: User) -> UserLoginResponse:
    role_name = user.role.role_name if user.role else None
    permission_ids = [up.permission_id for up in user.permissions]

    token = create_access_token(subject=user.user_id, role=user.role.role_name)

    return UserLoginResponse(
        token=token,
        user={
            "userId": user.user_id,
            "email": user.email,
            "firstName": user.first_name,
            "lastName": user.last_name,
            "role": role_name,
            "permissions": permission_ids
        }
    )

def login_user(db: Session, login: UserLogin) -> UserLoginResponse:
    user = user_repo.get_user_by_email(db, login.email)
    if not user or not bcrypt.verify(login.password, user.password_hash):
        raise Error.unauthorized("Invalid credentials")
    return _generate_login_response(user)

def register_user(db: Session, user: UserCreate) -> UserLoginResponse:
    if user_repo.get_user_by_email(db, user.email):
        raise Error.bad_request("Email already registered")
    new_user = user_repo.create_user(db, user)
    default_permission_ids = [9, 10, 11, 12]
    user_permission_repo.set_user_permissions(db, new_user.user_id, default_permission_ids)
    return _generate_login_response(new_user)



def get_user_info(db: Session, user_id: str) -> UserInfoResponse:
    user = user_repo.get_user_by_id(db, user_id)
    if not user:
        raise Error.not_found("User not found")


    permission_ids = [int(p.permission_id) for p in user.permissions]
    role_name = user.role.role_name if user.role else None

    return UserInfoResponse(
        first_name=user.first_name,
        last_name=user.last_name,
        email=user.email,
        role_name=role_name,
        permission_ids=permission_ids
    )

def list_users(db: Session, skip: int = 0, limit: int = 10):
    users = user_repo.get_users_paginated(db, skip, limit)
    total = user_repo.count_users(db)

    results = []
    for user in users:
        permission_ids = [int(p.permission_id) for p in user.permissions]
        role_name = user.role.role_name if user.role else None

        results.append({
            "first_name": user.first_name,
            "last_name": user.last_name,
            "email": user.email,
            "role_name": role_name,
            "permission_ids": permission_ids
        })

    return {
        "total": total,
        "users": results
    }

def update_user_info(db: Session, user_id: str, update_data: UpdateUserInfoRequest):
    user = user_repo.get_user_by_id(db, user_id)
    if not user:
        raise Error.not_found("User not found")
    if update_data.email and update_data.email != user.email:
        existing_user = user_repo.get_user_by_email(db, update_data.email)
        if existing_user:
            raise Error.bad_request("Email already in use")

    return user_repo.update_user_info(db, user, update_data)

def change_password(db: Session, user_id: str, request: ChangePasswordRequest):
    user = user_repo.get_user_by_id(db, user_id)
    if not user:
        raise Error.not_found("User not found")

    if not bcrypt.verify(request.old_password, user.password_hash):
        raise Error.unauthorized("Old password is incorrect")

    user_repo.update_password(db, user, request.new_password)
    return SuccessResponse.ok("Password updated successfully")


def update_user_permissions_by_email(db, email: str, permission_ids: List[int]):
    user = user_repo.get_user_by_email(db, email)
    if not user:
        raise Error.not_found("User with this email not found")

    user_permission_repo.set_user_permissions(db, user.user_id, permission_ids)
    return user








